#include <iostream>

#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>

#include <assert.h>
#include <vector>

#include <Windows.h> //Sleep

#include <memory> //std::shared_ptr    std::unique_ptr

#include "BlockingQueue.h"
#include "BoundedBlockingQueue.h"


class Test
{
public:
    Test() {}

    void creatThread(int count)
    {
        for (int n = 0; n<count; ++n)
        {
            threadPool.emplace_back(new std::thread(&Test::threadWork, this));
        }
    }

    void run()
    {
        for (int n=0; n<100; ++n)
        {
            char buf[40];
            sprintf(buf, "num:%d", n);
            std::cout << "  <<<<<<set " << buf << " sid:" << std::this_thread::get_id() << std::endl;
            queue.enqueue(buf);
        }
    }

    void joinAll()
    {
        for (auto& t : threadPool)
        {
            char buf[40];
            sprintf(buf, "end");
            queue.enqueue(buf);
        }

        for (auto& t : threadPool)
        {
            if (t->joinable())
            {
                t->join();
            }
        }
    }


private:
    void threadWork()
    {
        std::cout << "sub thread start " << std::this_thread::get_id() << std::endl;
        bool running = true;
        while (running)
        {
            std::string value = queue.dequeue();
            std::cout << ">>>>>>  get " << value << " sid:" << std::this_thread::get_id() << std::endl;
            running = (value != "end");
        }
        std::cout << "sub thread stop" << std::endl;
    }


    BlockingQueue<std::string> queue;
    std::vector<std::unique_ptr<std::thread>> threadPool;
};

class Test2
{

};



void testMove()
{
    BoundedBlockingQueue<std::unique_ptr<int>> queue(10);
    queue.enqueue(std::unique_ptr<int>(new int(42)));
    std::unique_ptr<int> x = queue.dequeue();
    printf("took %d\n", *x);
    *x = 123;
    queue.enqueue(std::move(x));
    std::unique_ptr<int> y;
    y = queue.dequeue();
    printf("took %d\n", *y);
}

int main()
{
    std::cout << "Hello World!" << std::endl;

    std::cout << "main thread start " << std::this_thread::get_id() << std::endl;

    Test t;
    t.creatThread(5);
    t.run();
    t.joinAll();

    std::cout << "main thread stop" << std::endl;

    testMove();

    return 0;

}
